﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Flash.Internal;

namespace Flash
{
    public abstract class SendAndLoadHandler : LoadVarsHandler
    {
        private const string DEFAULT_ACTION_FIELD = "action";
        private string _actionFieldName;

        #region Constructors

        public SendAndLoadHandler()
            : base()
        {
            _actionFieldName = DEFAULT_ACTION_FIELD;
        }

        public SendAndLoadHandler(bool returnError)
            : base(returnError)
        {
            _actionFieldName = DEFAULT_ACTION_FIELD;
        }

        public SendAndLoadHandler(bool returnError, string errorFieldName)
            : base(returnError, errorFieldName)
        {
            _actionFieldName = DEFAULT_ACTION_FIELD;
        }

        public SendAndLoadHandler(string actionFieldName)
            : base()
        {
            _actionFieldName = actionFieldName;
        }

        public SendAndLoadHandler(string actionFieldName, bool returnError)
            : base(returnError)
        {
            _actionFieldName = actionFieldName;
        }

        public SendAndLoadHandler(string actionFieldName, bool returnError, string errorFieldName)
            : base(returnError, errorFieldName)
        {
            _actionFieldName = actionFieldName;
        }

        #endregion

        protected override void ProcessRequest()
        {
            string action = null;
            var parameters = new Dictionary<string, string>();

            if (Context.Request.QueryString.AllKeys.Contains(_actionFieldName))
            {
                action = Context.Request.QueryString[_actionFieldName];
            }

            foreach (string key in Context.Request.Form.AllKeys)
            {
                if (key != _actionFieldName || action != null)
                {
                    parameters.Add(key, Context.Request.Form[key]);
                }
                else
                {
                    action = Context.Request.Form[key];
                }
            }

            if (string.IsNullOrEmpty(action))
            {
                throw new InvalidOperationException(string.Format("The '{0}' field is missing.", _actionFieldName));
            }

            InvokeMethod(action, parameters);
        }

        private void InvokeMethod(string action, Dictionary<string, string> parameters)
        {
            var method = ReflectionHelper.FindActionMethod(this.GetType(), action, parameters);

            if (method == null)
            {
                throw new InvalidOperationException(string.Format("No overload for method '{0}' with matching signature in '{1}' controller.",
                    action, this.GetType().FullName));
            }

            if (!ReflectionHelper.CheckMemberAccessForPrincipal(User, method))
            {
                throw new AccessDeniedException();
            }

            var orderedParameters = method.GetParameters().Select(x => ReflectionHelper.Parse(parameters[x.Name], x.ParameterType)).ToArray();
            method.Invoke(this, orderedParameters);
        }
    }
}